/**
 * 这是一个使用 C++ 实现的 TCP 服务端程序。它的功能是监听指定端口，把客户端发送的
 * 内容输出到标准输出，然后返回一个应答消息。后续循环监听客户端的消息，但是不
 * 回复。
 *
 * 程序的使用方法是，在终端启动时指定参数，./tcp_server port，port是服务器端口。
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#include <cstdlib>
#include <thread>
#include <iostream>

using namespace std;

class ClientConnect{
private:
    int socketId;
    socklen_t *lengthOfSocketAddress;
    sockaddr *peerAddress;
    int peerSocket;
    char *buffer;
public:
    ClientConnect(int socketId) {
        this->socketId = socketId;
        this->lengthOfSocketAddress = new socklen_t(sizeof(sockaddr));
        this->buffer = new char[100];
        peerAddress = new sockaddr();
        peerSocket = accept(socketId, peerAddress, lengthOfSocketAddress);
    }
    ~ClientConnect() {
        if (-1 != peerSocket && 0 != shutdown(peerSocket, SHUT_RDWR)) {
            cout << "Shutdown client socket fail" << endl;
            perror("Error info ");
        }
        if (-1 != peerSocket) {
            close(peerSocket);
        }
        delete lengthOfSocketAddress;
        delete peerAddress;
        delete[] buffer;
    }
    void runThread() {
        if (-1 == peerSocket) {
            cout << "peerSocket is -1, accept fail!" << endl;
            return;
        }
        ssize_t recvLength;
        if ((recvLength = recv(peerSocket, buffer, 99, 0)) <= 0) {
            perror("Receive data fail");
            return;
        }
        buffer[recvLength] = '\0';
        cout << "Data length: " << recvLength << endl;
        cout << buffer << endl;
        string message = "Hi, there.";
        ssize_t sendLength = message.length();
        ssize_t realSendLength = send(peerSocket, message.c_str(), sendLength, 0);
        if (sendLength != realSendLength) {
            perror("Send error");
            return;
        }
        cout << "Send data, length=" << realSendLength << endl;
        while (true) {
            if ((recvLength = recv(peerSocket, buffer, 99, 0)) <= 0) {
                perror("Receive data fail");
                return;
            }
        }
    }
};

int main(int argc, char **argv) {
    if (argc < 2) {
        cout << "Usage: ./tcp_server port" << endl;
        return -1;
    }
    auto port = atoi(argv[1]);
    cout << "Port: " << port << endl;

    // 创建 socket
    auto socketId = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == socketId) {
        cout << "Socket creation failed." << endl;
        return -1;
    }

    try {
        // 配置监听地址信息
        auto addressInfo = new sockaddr_in();
        addressInfo->sin_family = AF_INET;
        addressInfo->sin_port = htons(port);
        addressInfo->sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有网络发送过来的请求
        if (0 != bind(socketId, (sockaddr *)addressInfo, sizeof(sockaddr))) {
            delete addressInfo;
            perror("Bind error ");
            throw "Server start fail.";
        }
        cout << "Bind success" << endl;
        if (0 != listen(socketId, SOMAXCONN)) {
            delete addressInfo;
            perror("Fail, can't listen ");
            throw "Server start fail.";
        }
        cout << "Listening..." << endl;
        ClientConnect* clientConnect;
        thread* clientThread;
        while (true) {
            clientConnect = new ClientConnect(socketId);
            clientThread = new thread([](ClientConnect* clientConnect) {
                clientConnect->runThread();
                delete clientConnect;
            }, clientConnect);
            clientThread->detach();
        }
        delete addressInfo;
    } catch (const char *error) {
        cout << "Error, " << error << endl;
    }

    // 关闭socket
    if (0 != shutdown(socketId, SHUT_RDWR)) {
        cout << "Shutdown socket fail" << endl;
        perror("Error info ");
    }
    close(socketId);
    return 0;
}
